package 邮戳锁;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * @program: algorithm
 * @description:
 * @author: 陈恩涛
 * @create: 2022-09-14 23:04
 **/
public class StampedLockDemo {

    static int number = 37;

    static StampedLock stampedLock = new StampedLock();

    public void write() {
        final long stamp = stampedLock.writeLock();
        System.out.println(Thread.currentThread().getName() + "\t写线程准备就绪");
        try {
            number = number + 13;
            System.out.println(Thread.currentThread().getName() + "\t写线程完成修改");
        } finally {
            stampedLock.unlockWrite(stamp);
        }
    }

    public void optimisticRead() {
        long stamp = stampedLock.tryOptimisticRead();
        int result = number;
        String isUpdated = stampedLock.validate(stamp) ? "无" : "有";
        System.out.println("当前时间点邮戳是否被修改：" + isUpdated);
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            isUpdated = stampedLock.validate(stamp) ? "无" : "有";
            System.out.println("当前时间点邮戳是否被修改：" + isUpdated);
        }
        if (!stampedLock.validate(stamp)) {
            System.out.println("有其他线程执行过写操作");
            stamp = stampedLock.readLock();
            try {
                System.out.println("乐观读升级到悲观读");
                result = number;
                System.out.println("悲观读后，result为" + result);
            }finally {
                stampedLock.unlockRead(stamp);
            }
        }
    }

    public void read() {
        final long stamp = stampedLock.readLock();
        System.out.println(Thread.currentThread().getName() + "\t come in, read lock code block, 4 seconds later continue ...");
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t正在读取中……");
        }
        try {
            int result = number;
            System.out.println(Thread.currentThread().getName() + "\t 获得成员变量值result:" + result);
            System.out.println("写线程没有修改成功，有线程持有读锁的时候，写锁无法获取");

        }finally {
            stampedLock.unlockRead(stamp);
        }
    }



    public static void main(String[] args) {
        final StampedLockDemo stampedLockDemo = new StampedLockDemo();

        new Thread(() ->{
            stampedLockDemo.optimisticRead();
        },"乐观读线程").start();

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            stampedLockDemo.write();
        },"写线程").start();

        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + "最终获取到result值为" + number);
    }
}

